package controller.thread_pool_solver;

import java.util.ArrayDeque;
import java.util.Queue;

import solvers.LeaderResult;
import solvers.LeaderSolver;
import solvers.RivalResult;
import solvers.RivalSolver;

public class Thread4ThreadPool implements Runnable {
	// Mutex
	private Object general_mutex = new Object();
	private static final Object global_mutex = new Object();
	// Main data
	private boolean shutdown = false;
	private boolean terminated = false;

	private Queue<Task> tasks;
	private Queue<Result> results;

	private RivalSolver rivalSolver = null;
	
	public Thread4ThreadPool() {
		tasks = new ArrayDeque<Task>();
		results = new ArrayDeque<Result>();
	}
	
	public void addTask(Task task) {
		synchronized (general_mutex) {
			tasks.add(task);
		}
	}
	
	/**
	 * This methods waits until tasks will empty.
	 * After that it returns results.
	 */
	public Queue<Result> getResults() {
		while(true) {
			synchronized (general_mutex) {
				if(tasks.isEmpty()) {
					Queue<Result> re_results = results;
					results = new ArrayDeque<Result>();
					return re_results;					
				}
			}
			
			try {
				Thread.sleep(100);
			} catch (InterruptedException ex) {
				// TODO
			}
		}
	}
	
	public void shutdown() {
		synchronized (general_mutex) {
			shutdown = true;
		}
	}
	
	public boolean isTerminated() {
		synchronized (general_mutex) {
			return terminated;
		}
	}
	
	@Override
	public void run() {
		while(true) {
			Task current_task = null;
			synchronized (general_mutex) {
				if(shutdown)
					break;
				if(!tasks.isEmpty())
					current_task = tasks.poll();
			}
			if(current_task != null) {
				RivalResult riv_res = null;
				LeaderResult lead_res = null;
				//synchronized (global_mutex) {
					lead_res = LeaderSolver.solve(current_task.x, current_task.w, current_task.p);
	
					if (rivalSolver == null || rivalSolver.getM() != current_task.x.length || rivalSolver.getN() != current_task.w.length) {
						if (rivalSolver != null)
							rivalSolver.close();
						System.err.println("rival solver created");
						rivalSolver = new RivalSolver(current_task.x.length, current_task.w.length);
					}
					
					riv_res = rivalSolver.solve(lead_res.x, current_task.w, current_task.g,  current_task.r);
				//}
				// create ResultTask4Thread and return to ThreadPool
				double leader_income = 0;
				for (int i = 0; i < riv_res.z.length; i++) {
					leader_income += current_task.w[i] * riv_res.z[i];	
				}
				
				Result result = new Result(lead_res.x, riv_res.y, riv_res.z, leader_income, riv_res.income);
				
				synchronized (general_mutex) {
					results.add(result);
				}
				continue;
			}
			try {
				Thread.sleep(10);
			} catch (InterruptedException ex) {}
		}
		// set terminated variable to true
		synchronized (general_mutex) {
			terminated = true;
		}
	}
}
